Imports Microsoft.VisualBasic

Imports System.Drawing
Imports System.Web.HttpContext
Imports System.IO
Imports System.Data
Imports System.Xml

Imports Visio.VisSectionIndices
Imports Visio.VisRowIndices
Imports Visio.VisCellIndices

Imports System.Configuration.ConfigurationManager
Imports My

Imports System.Collections.Specialized
Imports System.Web.UI.DataSourceSelectArguments


Namespace HIPO

    Public Class aTextFile

#Region "Class Variables"
        Private mStaleDate As Date

        Protected _
               FileLines$(), _
 _
               LineCommand$, _
 _
               FilePath$, _
               FileExtension$, _
 _
               PrevLine$, _
               CurrentLine$, _
               NextLine$


        Public WholeText$, _
               FilePathName$, _
               FileName$, _
               Depth%

        Protected LineTokens As New ArrayList

        Protected Comments$(0)
        Protected MaxCommentLines% = ConfigurationManager.AppSettings("MaxCommentLines")

        Private CommentKeys$() = ConfigurationManager.AppSettings("CobolCommentKeys").Split(",")

        Protected FileDate As Date, _
                  Target$ = "0"

        Protected nLine& = 0

        Public FileID% = 0

        Public sdsBatCalledFiles, _
                sdsFileCommentLines, _
                sdsTextFiles, _
                sdsUsers, _
                sdsUserVSDFiles, _
                sdsCommentsDictionary, _
                sdsTreeNodes As SqlDataSource

        Protected BatCalledFileList As New ArrayList


        'Public Structure ofFileStats
        '    Dim Path As String
        '    Dim Name As String
        '    Dim Size As Long
        '    Dim ModDate As Date
        'End Structure

#End Region

#Region "Properties"
        Public Property StaleDate() As Date
            Get
                Return mStaleDate
            End Get

            Set(ByVal value As Date)
                mStaleDate = value
                If FileDate >= StaleDate Then Target = "_blank"
            End Set

        End Property
#End Region

#Region "Constructor/Destructor"
        Sub New(ByVal psFilePathName As String, Optional ByVal pbTextOnly As Boolean = False)
            Try


                FilePathName = psFilePathName
                SplitUpFilePathName()

                Dim fsrFile As StreamReader = File.OpenText(psFilePathName)
                FileDate = File.GetLastWriteTime(psFilePathName)
                Dim nFileSize& = 0

                WholeText = fsrFile.ReadToEnd
                If pbTextOnly = True Then
                    Exit Sub
                End If

                sdsTextFiles = Current.Session("sdsTextFiles")
                sdsTreeNodes = Current.Session("sdsTreeNodes")
                sdsUserVSDFiles = Current.Session("sdsUserVSDFiles")
                sdsBatCalledFiles = Current.Session("sdsBatCalledFiles")
                sdsFileCommentLines = Current.Session("sdsFileCommentLines")
                sdsUsers = Current.Session("sdsUsers")
                sdsCommentsDictionary = Current.Session("sdsCommentsDictionary")

                GetFileID(psFilePathName)

                Dim saDelim$() = {vbCrLf}
                FileLines = WholeText.Split(saDelim, StringSplitOptions.RemoveEmptyEntries)

                fsrFile.Close()
                fsrFile = Nothing

                'AddToFileStats(IO.Path.GetFileName(psFilePathName), IO.Path.GetDirectoryName(psFilePathName))

                'Populate Line buffers so can know if file is empty (CurrentLine=Nothing)
                GetNextLine()
                nLine = 0

            Catch exFileNotfound As System.IO.FileNotFoundException
                'If can't find source for an exe -- note it and keep processing
                'If Path.GetExtension(psFilePathName).ToLower = ".pco" Then
                FileName &= ConfigurationManager.AppSettings("FileNotFound")


            End Try

        End Sub

        'Need finalize
#End Region

#Region "Methods"

        Public Sub GetNextLine()

            PrevLine = CurrentLine
            CurrentLine = Nothing
            LineTokens = Nothing
            LineCommand = Nothing

            Dim sLine$ = ""
            For iLine As Long = nLine To FileLines.Length - 1
                sLine$ = FileLines(iLine).Trim(" ", Chr(10), Chr(9))
                If sLine.Length Then
                    nLine = iLine + 1
                    CurrentLine = sLine
                    Exit For
                End If
            Next

            If Not IsNothing(CurrentLine) AndAlso CurrentLine.Length > 0 Then
                GetLineTokens()
            End If

            NextLine = Nothing
            For iLine As Long = nLine To FileLines.Length - 1
                Dim sNextLine$ = FileLines(iLine).Trim(" ", Chr(10), Chr(9))
                If sNextLine.Length Then
                    NextLine = sNextLine
                    Exit For
                End If
            Next

            'Return CurrentLine
        End Sub

        Protected Sub GetLineTokens()
            Dim saDelims$() = {" ", Chr(9)}
            Dim saTokens$() = CurrentLine.Split(saDelims, StringSplitOptions.RemoveEmptyEntries)
            LineTokens = New ArrayList
            LineTokens.InsertRange(0, saTokens)


            If Not IsNothing(LineTokens) AndAlso LineTokens.Count > 0 Then
                LineCommand = LineTokens(0).ToLower.Trim(" ", Chr(9))
            Else
                LineCommand = Nothing
            End If
        End Sub

        Protected Sub SplitUpFilePathName()
            FileName = IO.Path.GetFileNameWithoutExtension(FilePathName)
            FilePath = IO.Path.GetDirectoryName(FilePathName)
            FileExtension = IO.Path.GetExtension(FilePathName).ToLower.Remove(0, 1)
        End Sub


        Protected Sub AddCommentLine(Optional ByVal psRemove$ = "::")
            If Comments.Length = MaxCommentLines Then
                Exit Sub
            End If

            'Collect all comments and mark them with 1, if match our words list, or 0,
            Dim saDelim$() = {"*"}
            Dim saLine$() = CurrentLine.Split(saDelim, StringSplitOptions.RemoveEmptyEntries)
            If saLine.Length Then
                Dim sComment$ = CurrentLine.Replace("*", "").Trim(" ", Chr(9))
                sComment = sComment.Replace(psRemove, "").Trim(" ", Chr(9))
                Dim bFound As Boolean = False
                For Each sKey As String In CommentKeys
                    If CurrentLine.ToLower.Contains(sKey) Then
                        bFound = True
                        Exit For
                    End If
                Next
                Comments(Comments.Length - 1) = IIf(bFound, "1,", "0,") & sComment
                ReDim Preserve Comments(Comments.Length)
            End If
        End Sub

        'Protected Sub AddToFileStats(ByVal psFileName$, ByVal psFilePath$)

        '    Dim oFileStatsTable As New HIPO.aJobStatsFile()

        '    oFileStatsTable.AddToFileStats(psFileName, psFilePath)

        'End Sub


        Protected Sub AddNode(ByRef poNode As TreeNode)
            Dim bExpanded As Boolean = False
            If poNode.Expanded.HasValue Then
                bExpanded = poNode.Expanded.Value
            End If

            'Add the file id to the BatCalledFileList if not already there
            'If the poNode.ImageToolTip is numeric, it's a FileID
            'if the BatCalledFileList doesn't contain the FileID already
            'add the FileID to the BatCalledFileList

            'Add to the TreeNodes table
            With sdsTreeNodes
                With .InsertParameters
                    !VSDFileID.DefaultValue = 0 'Current.Session("VSDFileID")
                    If IsNothing(poNode.Parent) Then
                        Current.Session("Node#") = 1
                        !ParentNodeID.DefaultValue = 0
                    Else
                        !ParentNodeID.DefaultValue = poNode.Parent.NavigateUrl
                    End If
                    poNode.NavigateUrl = Current.Session("Node#")
                    !NodeId.DefaultValue = poNode.NavigateUrl
                    !Text.DefaultValue = poNode.Text
                    !Value.DefaultValue = poNode.Value
                    !Tooltip.DefaultValue = poNode.ToolTip 'not sure if here should be comment id
                    !ImageTooltip.DefaultValue = poNode.ImageToolTip
                    !Expanded.DefaultValue = bExpanded
                    !Checked.DefaultValue = poNode.Checked
                    !Selected.DefaultValue = poNode.Selected
                    !Target.DefaultValue = poNode.Target
                    !Depth.DefaultValue = poNode.Depth
                End With
                Try
                    .Insert()
                Catch
                End Try


            End With

            Current.Session("Node#") += 1
        End Sub

        Protected Sub AddNodeComments(ByVal poNode As TreeNode, ByVal psaComments$())
            'Save notes !!
            'If no notes don't save
            If psaComments.Length = 0 Or (psaComments.Length = 1 AndAlso IsNothing(psaComments(0))) Then
                Exit Sub
            End If

            With sdsFileCommentLines
                With .SelectParameters
                    !FileID.DefaultValue = FileID
                End With

                Dim dv As DataView = .Select(Empty)
                If dv.Table.Rows.Count Then
                    'Already have comments, which may have been updated, leave for now
                    'may be able to update if the file is newer than the comments
                Else
                    'Add the comment lines
                    .InsertParameters!FileID.DefaultValue = FileID
                    For iLine As Integer = 1 To psaComments.Length
                        If Not IsNothing(psaComments(iLine - 1)) Then
                            Dim saLine$() = psaComments(iLine - 1).Split(",")
                            If saLine.Length > 1 AndAlso saLine(1).Trim.Length > 0 Then
                                With .InsertParameters
                                    !LineId.DefaultValue = iLine
                                    !IsVisibleLine.DefaultValue = CBool(saLine(0))
                                    !CommentLine.DefaultValue = saLine(1)
                                End With
                                Try
                                    .Insert()
                                Catch
                                End Try

                            End If
                        End If
                    Next

                End If

            End With

        End Sub

        Protected Sub GetFileID(ByVal psFilePathName$)
            'If already have an id then return it
            'Otherwise, add a new TextFile record

            If IsNothing(sdsTextFiles) Then
                Exit Sub
            End If

            With sdsTextFiles
                With .SelectParameters
                    !Name.DefaultValue = IO.Path.GetFileNameWithoutExtension(psFilePathName)
                    !Path.DefaultValue = IO.Path.GetDirectoryName(psFilePathName)
                    !Type.DefaultValue = IO.Path.GetExtension(psFilePathName).TrimStart(".")
                End With
                Dim dv As DataView = .Select(Empty)
                If dv.Table.Rows.Count = 0 Then
                    With .InsertParameters
                        !Name.DefaultValue = sdsTextFiles.SelectParameters!Name.DefaultValue
                        !Path.DefaultValue = sdsTextFiles.SelectParameters!Path.DefaultValue
                        !Type.DefaultValue = sdsTextFiles.SelectParameters!Type.DefaultValue
                        !Size.DefaultValue = WholeText.Length
                        !Date.DefaultValue = IO.File.GetLastWriteTime(psFilePathName)
                    End With
                    .Insert()
                    dv = .Select(Empty)
                End If

                FileID = dv.Table.Rows(0)!FileID

            End With
        End Sub


#End Region


    End Class


    Public Class aBatchTextFile
        Inherits aTextFile

        Public FileNodes As New ArrayList
        Public NodePathFileNames As New ArrayList

        Public MaxDepth% = 0

        Private BatFileId% = FileID

        Public DrawingPageSize As SizeF

        Private CalledPrograms As New ArrayList(ConfigurationManager.AppSettings("CalledPrograms").Split(","))

        Sub New(ByVal psFilePathName$)
            MyBase.New(psFilePathName)

        End Sub

        Public Sub CreateTree(ByVal psBatchFilePathName$, ByRef pTree As TreeView, ByRef pViewState As StateBag)

            'Get or add a VSDFileID for this tree
            GetVSDFileID(psBatchFilePathName)

            'rootnode.text = batch file name
            Dim oRootNode As TreeNode
            oRootNode = New TreeNode( _
                 IO.Path.GetFileName(psBatchFilePathName), "Terminator")

            'Add rootnode to BatchTree
            pTree.Nodes.Clear()

            pTree.Nodes.Add(oRootNode)
            AddNode(oRootNode)

            'Recursively adds nodes to the treeview
            Dim oBat As New HIPO.aBatchTextFile(psBatchFilePathName)
            Dim sComments$ = oBat.ReadBatch(oRootNode, pViewState)
            'AddNodeComments(oRootNode, Comments)

            'Add end terminator shape
            Dim oEndNode As New TreeNode("End", "Terminator")

            oRootNode.ChildNodes.Add(oEndNode)
            AddNode(oEndNode)

            SaveBatCalledFileList()

            Dim oPageSize As New aPageSize(Depth, MaxDepth)
            oPageSize.SetPageDepth(oRootNode)
            DrawingPageSize = oPageSize.PageSize

        End Sub

        Sub SaveBatCalledFileList()
            'Add the BatCalledFileList to the sdsBatCalledFiles dataview
            'by cycling thru each BatCalledFileList entry 
            '   If it's not already in the table,
            '       insert it along with the BatFileId

        End Sub

        Private Sub GetVSDFileID(ByVal psBatchFilePathName$)
            Dim sFileName$ = _
            IO.Path.ChangeExtension(IO.Path.GetFileName(psBatchFilePathName), _
             Current.Session("UserName"))

            With sdsUserVSDFiles
                With .SelectParameters
                    !VSDFileName.DefaultValue = sFileName
                End With

                Dim dv As DataView = .Select(New DataSourceSelectArguments)

                If dv.Table.Rows.Count = 0 Then
                    'NEW VSDFile
                    With .InsertParameters
                        !VSDFileName.DefaultValue = sFileName
                        !UserID.DefaultValue = Current.Session("UserID")
                        !BatFileId.DefaultValue = BatFileId
                    End With

                    .Insert()

                    dv = .Select(New DataSourceSelectArguments)
                Else
                    'Remove the old nodes or supply them?
                    With sdsTreeNodes
                        With .DeleteParameters
                            !VSDFileID.DefaultValue = Current.Session("VSDFileID")
                        End With
                        .Delete()
                    End With

                End If

                Current.Session("VSDFileID") = dv.Table.Rows(0)!VSDFileID

            End With
        End Sub

        Public Overloads Sub GetNextLine(ByVal pViewState As StateBag)
            MyBase.GetNextLine()

            If Not IsNothing(CurrentLine) AndAlso CurrentLine.Length > 0 Then

                ReplaceLineSymbols(pViewState)

                MyBase.GetLineTokens()

            End If
        End Sub

        Private Sub ReplaceLineSymbols(ByVal pViewState As StateBag)
            If CurrentLine.Contains("%") Then
                'Replace any environment vars
                For Each sKey As String In pViewState.Keys()
                    CurrentLine = CurrentLine.ToUpper.Replace(String.Format("%{0}%", sKey.ToUpper), pViewState(sKey))
                Next
            End If
        End Sub

        Function ReadBatch$(ByRef poFromNode As TreeNode, ByRef pViewState As StateBag)
            Dim sCardFile$ = ""
            Dim sOutFile$ = ""

            Dim sComment$ = ""

            'While more lines
            While Not CurrentLine Is Nothing

                GetNextLine(pViewState)

                Select Case LineCommand
                    Case "set"
                        ProcessSetCmd(pViewState)

                    Case "call", "sqlplus"
                        'If the first token is "call" then
                        'Split the second token (. delimited) into parts
                        'Get the called file name 
                        Dim sFilePathName$ = LineTokens(1).Trim(" ", Chr(9))
                        Dim sFileName$ = Path.GetFileNameWithoutExtension(sFilePathName)

                        Dim sCallType$ = ProcessCallCmd(sFileName, sFilePathName)
                        Select Case sCallType
                            Case "log"
                                ProcessLogCall()

                            Case "bat"
                                ProcessBatCall(sFileName, poFromNode, pViewState)

                                'Skip batch files on the bypass list
                                If pViewState("Bypass").ToString.ToLower.Contains(sFileName.ToLower) Then
                                    GoTo NextLine
                                End If

                                'Add node to tree
                                AddBatProcessNode(poFromNode, pViewState, sFileName, sComment, sFilePathName)

                            Case "exe"
                                ProcessExeCall(poFromNode, pViewState, sFileName, sComment, sFilePathName)

                            Case "sqlplus", "sql"
                                ProcessSqlCall(poFromNode, pViewState, sFileName, sComment, sFilePathName)

                            Case "" 'its a label
                                GoTo NextLine

                            Case Else '(another called file type?)
                                ProcessOtherCalls(poFromNode, pViewState, sCallType, sFileName, sComment, sFilePathName)

                        End Select

                    Case Else
                        '	ElseIf its a comment line
                        '		Add line to comment line array, strip off leading :: chars
                        If Not IsNothing(CurrentLine) AndAlso CurrentLine.StartsWith("::") Then
                            'This is a comment line, so add first fifty lines to an array
                            AddCommentLine("::")

                        End If

                End Select

NextLine:
            End While
            '        Return comments
            poFromNode.ImageToolTip = FileID
            AddNodeComments(poFromNode, Comments)
            Return ""
        End Function

        Private Sub ProcessSetCmd(ByRef pViewState As StateBag)
            Dim sep() As Char = {" "}

            Dim sFilePathName$ = LineTokens(1)
            'Dim sFileName$ = Path.GetFileNameWithoutExtension(sFilePathName)
            Dim saParts$() = LineTokens(1).Split("=")

            'The last part is the call type
            Dim sVarname$ = saParts(0).ToLower.Trim(" ", Chr(9))
            Dim sValue$ = ""
            If saParts.Length > 1 Then
                sValue = saParts(1)
            End If

            'Update environment variables, unless being cleared
            If saParts.Length >= 2 Then
                If sValue.Length And Not IsNumeric(sValue.Replace("%", "")) Then
                    pViewState(sVarname) = sValue
                    ''System.Diagnostics.Debug.Print(String.Format("Setting {0}={1}", sVarname, sValue))
                End If
            End If

        End Sub

        Private Function ProcessCallCmd$(ByRef psFileName$, ByRef psFilePathName$)

            Dim sCallType$ = ""

            If LineTokens.Count > 1 Then

                'If LineTokens(1).ToLower.Contains("clearvars") Then Stop

                If CalledPrograms.Contains(psFileName.ToLower) Then
                    'calling a program on our list, like sqlplus
                    sCallType = psFileName.ToLower

                ElseIf Path.HasExtension(psFilePathName) Then
                    'The extension is the call type
                    'The argument has an extension
                    sCallType = Path.GetExtension(psFilePathName).ToLower.Replace(".", "")

                Else
                    'the argument has no extension, look for it in next token


                    Try
                        If LineTokens.Count > 2 Then
                            If Path.HasExtension(LineTokens(2).Trim(" ", Chr(9))) Then
                                psFilePathName$ = LineTokens(2).Trim(" ", Chr(9))
                                sCallType = Path.GetExtension(psFilePathName).ToLower.Replace(".", "")
                            End If
                        End If
                    Catch
                    End Try
                End If
            End If

            psFileName = Path.GetFileNameWithoutExtension(psFilePathName)


            Select Case psFileName.ToLower
                Case "logmsg"
                    sCallType = "log"
                Case Else
                    If sCallType.Length <> 3 And sCallType <> "sqlplus" And Not sCallType.StartsWith(":") Then
                        ''System.Diagnostics.Debug.Print(psFileName & "[" & CurrentLine & "]" & vbCrLf & LineTokens.ToString)
                    End If

            End Select
            'Need to account for bat files w/o .bat extension

            'Need to get second arg .bat files
            Return sCallType
        End Function

        Private Sub ProcessLogCall()
        End Sub

        Private Sub ProcessBatCall(ByVal psFileName$, ByRef poFromNode As TreeNode, ByRef pViewState As StateBag)

            Select Case psFileName.ToLower

                Case "setoutfile"
                    ProcessCallSetOutFile(pViewState)

                Case "getnamedparm"
                    ProcessCallGetNamedParm(pViewState)

                Case "laserprint"
                    ProcessCallLaserPrint(pViewState)

            End Select

            Dim sParm$ = ""
            If Not IsNothing(pViewState("ShowFirstParm")) AndAlso pViewState("ShowFirstParm").ToString.Contains(psFileName.ToLower) Then
                If LineTokens.Count > 2 Then sParm = vbCrLf & LineTokens(2)
            ElseIf Not IsNothing(pViewState("ShowSecondParm")) AndAlso pViewState("ShowSecondParm").ToString.ToLower.Contains(psFileName) Then
                If LineTokens.Count > 3 Then sParm = vbCrLf & LineTokens(3)
            End If

        End Sub

        Private Sub AddBatProcessNode(ByRef poFromNode As TreeNode, ByVal pViewState As StateBag, ByRef psFileName$, ByRef psComment$, ByRef psFilePathName$)
            Dim oChildNode As New TreeNode(psFileName & vbCrLf & ".BAT", "Process")
            oChildNode.ImageToolTip = FilePathName
            oChildNode.ToolTip = psComment

            ''System.Diagnostics.Debug.Print(String.Format("Adding {0} to {1}", sFileName.Replace(vbCrLf, ""), poFromNode.Text))
            'If poFromNode.Text.StartsWith("SUPEST") Then Stop
            poFromNode.ChildNodes.Add(oChildNode)
            AddNode(oChildNode)

            'Do a recursive call to this subroutine
            If Not Path.IsPathRooted(psFilePathName) Then
                psFilePathName = Path.Combine(pViewState("BatchPath"), psFilePathName)
            End If

            Dim oChildBatchFile As New HIPO.aBatchTextFile(psFilePathName)
            psComment = oChildBatchFile.ReadBatch(oChildNode, pViewState)

            'AddNodeComments(oChildNode, psComment)

        End Sub

        Private Sub AddOtherPreparationNode(ByRef poFromNode As TreeNode, ByVal pViewState As StateBag, ByRef psFileName$, ByRef psComment$, ByRef psFilePathName$)
            'Add node to tree
            Dim oChildNode As New TreeNode(psFileName, "Preparation")
            oChildNode.ImageToolTip = psFilePathName
            oChildNode.ToolTip = psComment

            ''''System.Diagnostics.Debug.Print(String.Format("Adding {0} to {1}", sFileName, poFromNode.Text))
            poFromNode.ChildNodes.Add(oChildNode)
            AddNode(oChildNode)

            'sComment = ReadSQL(sFilePathName, oChildNode)
            'oChildNode.ToolTip = sComment
        End Sub

        Private Sub ProcessCallSetOutFile(ByRef pViewState As StateBag)
            If FileName <> "LASERPRINT" Then
                Dim sKeyName$ = "outFile"
                If LineTokens.Count > 2 Then
                    Dim sValueName$ = LineTokens(2)
                    If sValueName.Length Then
                        pViewState(sKeyName) = sValueName
                        pViewState("NAMEDPARM") = sValueName
                        ''System.Diagnostics.Debug.Print(String.Format("Setting {0}={1}", sKeyName, sValueName))
                    End If
                End If
            End If
        End Sub

        Private Sub ProcessCallGetNamedParm(ByRef pViewState As StateBag)
            Dim sValueName$ = ""
            Dim sKeyName$ = ""
            If LineTokens.Count > 4 Then
                sKeyName = LineTokens(2)
                sValueName = LineTokens(4)
            ElseIf LineTokens.Count > 3 Then
                sKeyName = LineTokens(2)
                sValueName = LineTokens(3)
            End If
            If sValueName.Length Then
                pViewState(sKeyName) = sValueName
                ''System.Diagnostics.Debug.Print(String.Format("Setting {0}={1}", sKeyName, sValueName))
                pViewState("namedParm") = sValueName
                ''System.Diagnostics.Debug.Print(String.Format("Setting {0}={1}", "namedParm", sValueName))
            End If


        End Sub

        Private Sub ProcessCallLaserPrint(ByRef pViewState As StateBag)
            'Add an output to the following exe
            Dim alArgs As New ArrayList(LineTokens(2).ToString.Split("|"))
            For Each sArg As String In alArgs
                Dim alParm As New ArrayList(sArg.Split("="))
                Select Case alParm(0).ToString.ToUpper
                    Case "FILE"
                        pViewState("fileName") = alParm(1).ToString
                        pViewState("cardinputfile") = pViewState("outFile")
                        Exit For
                        'Could pick up the other print info here
                End Select
            Next
        End Sub

        Private Sub ProcessExeCall(ByRef poFromNode As TreeNode, ByRef pViewState As StateBag, ByRef psFileName$, ByRef psComment$, ByRef psFilePathName$)
            'Replace the exe path name with the pco path name
            psFilePathName = Path.Combine(pViewState("Cobol"), psFileName & ".PCO")
            Dim oCobolFile As New aCobolTextFile(psFilePathName)

            If oCobolFile.FileName.Contains("NOT FOUND") Then
                'See if it's a .cob
                psFilePathName = psFilePathName.Replace(".PCO", ".COB")
                oCobolFile = New aCobolTextFile(psFilePathName)
            End If

            'Add node to tree
            Dim oChildNode As New TreeNode(oCobolFile.FileName & vbCrLf & ".EXE", "Predefined process")

            If Not oCobolFile.FileName.Contains("NOT FOUND") Then
                oChildNode.ToolTip = psComment
                oChildNode.ImageToolTip = psFilePathName

                psComment = oCobolFile.ReadPCO(oChildNode, pViewState)
            End If

            oChildNode.ToolTip = psComment


            Dim ViewStateKeys As New ArrayList
            ViewStateKeys.AddRange(pViewState.Keys)

            Dim ViewStateVals As New ArrayList
            ViewStateVals.AddRange(pViewState.Values)

            'See if any output FD's in the Cobol File
            Dim oOutputFD As HIPO.aCobolTextFile.ofCobolFD = Nothing
            Dim sOutputShape$ = ""

            Dim oInputFD As HIPO.aCobolTextFile.ofCobolFD = Nothing
            Dim sInputShape$ = ""

            'Pick the the first input and output FDs
            For Each oFD As HIPO.aCobolTextFile.ofCobolFD In oCobolFile.collCobolFDs

                Dim sShape$ = _
                 IIf(oFD.RecordSize = 0, "Sequential Data", _
                 IIf(oFD.RecordSize < 130, "Card", _
                 IIf(oFD.RecordSize < 135, "Document", _
                 IIf(oFD.RecordSize < 145, IIf(oFD.RecordType = "INPUT", "Sequential Data", "Paper Tape"), _
                 "Sequential Data"))))

                Select Case oFD.RecordType
                    Case "INPUT"
                        If IsNothing(oInputFD.Name) Then
                            oInputFD = oFD
                            sInputShape = sShape

                        End If

                    Case "OUTPUT"
                        If IsNothing(oOutputFD.Name) Then
                            oOutputFD = oFD
                            sOutputShape = sShape
                        End If

                End Select
            Next

            If Not IsNothing(oInputFD.Name) And pViewState("chkSkipEXEInputs") = False Then
                If IsNothing(oInputFD.ExternalFileName) Then oInputFD.ExternalFileName = oInputFD.Name
                '	Create a "card" childnode, CardNode 
                'puts input file (or cardfile) before EXE in tree
                Dim sCardFileName$ = Path.GetFileNameWithoutExtension(oInputFD.ExternalFileName)
                Dim sCardPathFileName$ = oInputFD.ExternalFileName
                If oInputFD.ExternalFileName.Contains(pViewState("batCard").ToString.ToLower) Then
                    If Not Path.HasExtension(oInputFD.ExternalFileName) Then sCardPathFileName &= ".crd"
                    sCardFileName &= vbCrLf & ".CRD"
                End If

                Dim oCardNode As New TreeNode(sCardFileName, sInputShape)
                oCardNode.ImageToolTip = sCardPathFileName
                oCardNode.Checked = True
                '	add childnode to CardNode, since this was a nested call, comment is attribute
                oCardNode.ChildNodes.Add(oChildNode)


                '	Add CardNode to FromNode
                poFromNode.ChildNodes.Add(oCardNode)
                AddNode(oCardNode)
                AddNode(oChildNode)
            Else
                poFromNode.ChildNodes.Add(oChildNode)
                AddNode(oChildNode)
            End If

            'Add data nodes, if any
            For Each oNode As TreeNode In oCobolFile.DataNodes
                oChildNode.ChildNodes.Add(oNode)
                AddNode(oNode)
            Next

            If Not IsNothing(oOutputFD.Name) Then
                '	add "txt" childnode, TxtNode, to childnode 
                'puts outfile after EXE and data nodes in tree

                Dim oTxtNode As New TreeNode(oOutputFD.ExternalFileName, sOutputShape)
                oChildNode.ChildNodes.Add(oTxtNode)
                AddNode(oTxtNode)
            End If



        End Sub

        Private Sub ProcessSqlCall(ByRef poFromNode As TreeNode, ByRef pViewState As StateBag, ByRef psFileName$, ByRef psComment$, ByRef psFilePathName$)
            psFilePathName$ = LineTokens(2).Trim(" ")

            For Each psFileName In LineTokens
                If psFileName.ToLower.Contains(".sql") Then
                    psFilePathName = psFileName.Replace("@", "")
                    Exit For
                End If
            Next

            If psFilePathName.ToUpper.StartsWith("SQL\") Then
                psFilePathName = psFilePathName.ToUpper.Replace("SQL\", pViewState("batSQL"))
            ElseIf psFilePathName.ToUpper.StartsWith("SQLPLUS\") Then
                psFilePathName = psFilePathName.ToUpper.Replace("SQLPLUS\", pViewState("batSQL"))
            End If

            Dim oSQLFile As New aSQLTextFile(psFilePathName)


            'Add node to tree
            'Dim oChildNode As New TreeNode(oSQLFile.FileName & vbCrLf & ".SQL", "Stored Data", Nothing,  oSQLFile.FilePathName , "0")
            Dim oChildNode As New TreeNode(oSQLFile.FileName & vbCrLf & ".SQL", "Stored Data")
            oChildNode.ImageToolTip = oSQLFile.FilePathName

            'oChildNode.ToolTip = sComment

            ''System.Diagnostics.Debug.Print(String.Format("Adding {0} to {1}", sFileName, poFromNode.Text))
            poFromNode.ChildNodes.Add(oChildNode)
            AddNode(oChildNode)

            psComment = oSQLFile.ReadSQL(oChildNode, pViewState)
            'AddNodeComments(oChildNode, psComment)
            'oChildNode.ToolTip = psComment
        End Sub

        Private Sub ProcessOtherCalls(ByRef poFromNode As TreeNode, ByRef pViewState As StateBag, ByVal psCallType$, ByRef psFileName$, ByRef psComment$, ByRef psFilePathName$)
            If psCallType.StartsWith(":") Then 'it's a label
            Else
                ''System.Diagnostics.Debug.Print(sFileName & "[" & CurrentLine & "]" & vbCrLf & LineTokens.ToString)
                'Add as a "Preparation" node
                For Each psFileName In LineTokens
                    If psFileName.ToLower.Contains(".") Then
                        psFilePathName = psFileName.Replace("@", "")
                        If psFilePathName.Split(Path.GetInvalidPathChars(), StringSplitOptions.RemoveEmptyEntries).Length = 1 _
                         AndAlso Path.HasExtension(psFilePathName) Then
                            psFileName = Path.GetFileName(psFilePathName)
                        End If
                        Exit For
                    End If
                Next

                AddOtherPreparationNode(poFromNode, pViewState, psFileName, psComment, psFilePathName)

            End If
        End Sub

        Private Sub ProcessCommentLine()

        End Sub

    End Class

    Public Class aCobolTextFile
        Inherits aTextFile

        Public HasCardFD As Boolean = False
        Public HasReportFD As Boolean = False
        Public HasTapeFD As Boolean = False

        Public DataNodes As New ArrayList

        Public Structure ofCobolFD
            Dim Name$
            Dim ExternalName$
            Dim ExternalFileName$
            Dim RecordName$
            Dim RecordSize%
            Dim RecordType$
        End Structure

        Public collCobolFDs As New Collection

        Private CurrentFD As New ofCobolFD

        Sub New(ByVal psFilePathName$)
            MyBase.New(psFilePathName)

            'Add exe files to filestats
            'AddToFileStats(Path.GetFileNameWithoutExtension(psFilePathName) & ".EXE", AppSettings("batBin"))

        End Sub

        Public Function ReadPCO(ByRef poFromNode As TreeNode, ByRef pViewState As StateBag)

            Dim _
            bInFileControl As Boolean = False, _
            bInDataDiv As Boolean = False, _
            bInWorkStorage As Boolean = False, _
            bInProcDiv As Boolean = False, _
            bInFD As Boolean = False

            While Not CurrentLine Is Nothing

                GetNextLine()

                Select Case LineCommand
                    Case "file-control", "file-control."
                        bInFileControl = True

                    Case "select"
                        If bInFileControl Then
                            'SELECT FDName
                            Dim sFDName$ = LineTokens(1)

                            'Start new ColbolFD
                            CurrentFD = New ofCobolFD
                            CurrentFD.Name = sFDName
                            CurrentFD.RecordSize = 0

                            'Add to FDs collection
                            collCobolFDs.Add(CurrentFD, sFDName.ToUpper)

                        End If

                    Case "assign"
                        If bInFileControl Then
                            'ASSIGN EXTERNAL ExternalName 
                            Dim sExternalName$ = LineTokens(2)
                            'Set External name
                            CurrentFD.ExternalName = sExternalName.ToLower.TrimEnd(".")
                            If CurrentFD.ExternalName.Contains("%") Then
                                'Need to resolve symbol
                                For Each sKey As String In pViewState.Keys()
                                    CurrentFD.ExternalName = CurrentFD.ExternalName.ToLower.Replace(String.Format("%{0}%", sKey.ToLower), pViewState(sKey))
                                Next

                            End If

                            'Get the external file name from the ViewState
                            If IsNothing(pViewState(CurrentFD.ExternalName)) Then
                                CurrentFD.ExternalFileName = "Unknown File"
                            Else
                                CurrentFD.ExternalFileName = pViewState(CurrentFD.ExternalName).ToLower.Replace(".", "")
                            End If

                            collCobolFDs.Remove(CurrentFD.Name)
                            collCobolFDs.Add(CurrentFD, CurrentFD.Name)

                        End If

                    Case "data"
                        'DATA DIVISION or DATA RECORD IS RecName (in FD)
                        If bInFD Then
                            'Add RecName to FD
                            CurrentFD.RecordName = LineTokens(3)
                            collCobolFDs.Remove(CurrentFD.Name)
                            collCobolFDs.Add(CurrentFD, CurrentFD.Name)
                        Else
                            bInFileControl = False
                            bInDataDiv = True
                        End If

                    Case "fd"
                        'FD FDname
                        If bInDataDiv Then
                            bInFD = True
                            'Get current FD by Name
                            CurrentFD = collCobolFDs(LineTokens(1).ToString.ToUpper)
                        End If

                    Case "record"
                        'RECORD CONTAINS 0133 CHARACTERS
                        If bInFD Then
                            'Set the Record Size
                            CurrentFD.RecordSize = Val(LineTokens(2))
                            collCobolFDs.Remove(CurrentFD.Name)
                            collCobolFDs.Add(CurrentFD, CurrentFD.Name)
                            bInFD = False
                        End If

                    Case "working-storage"
                        'WORKING-STORAGE SECTION
                        bInDataDiv = False
                        bInFD = False
                        bInWorkStorage = True

                    Case "procedure"
                        'PROCEDURE DIVISION
                        bInWorkStorage = False
                        bInProcDiv = True

                    Case "open"
                        'OPEN  INPUT FDName.
                        If bInProcDiv Then
                            'Set Record Type
                            Select Case LineTokens(1).ToString.ToUpper
                                Case "INPUT", "OUTPUT"
                                    CurrentFD = collCobolFDs(LineTokens(2).ToString.Replace(".", "").ToUpper)
                                    CurrentFD.RecordType = LineTokens(1).ToString.ToUpper
                                    collCobolFDs.Remove(CurrentFD.Name)
                                    collCobolFDs.Add(CurrentFD, CurrentFD.Name)
                            End Select
                        End If

                    Case "input", "output" 'Note current FD will habe already been set
                        If bInProcDiv Then
                            'INPUT FDName.
                            CurrentFD.RecordType = LineTokens(0).ToString.ToUpper
                            collCobolFDs.Remove(CurrentFD.Name)
                            collCobolFDs.Add(CurrentFD, CurrentFD.Name)
                        End If

                    Case "insert", "update", "delete", "create", "truncate", "drop"
                        'Add DATA node to tree
                        If bInProcDiv Then
                            Try
                                If LineTokens.Count = 1 Then
                                    'Need to read the next line and combine with this
                                    CurrentLine &= " " & NextLine
                                    'GoTo RedoLine
                                End If

                                'Need to add Cobol comments
                                If LineTokens.Count > 1 AndAlso LineTokens(1).ToUpper.StartsWith("INDEX") Then
                                Else
                                    'These nodes need to be added to an in-memory collection
                                    'of data nodes, since they have no parent node here
                                    Dim oChildNode As New TreeNode(CurrentLine.Split("(")(0).ToLower, "Data")
                                    oChildNode.ImageToolTip = FilePathName
                                    oChildNode.ToolTip = " "
                                    DataNodes.Add(oChildNode)
                                    'poFromNode.ChildNodes.Add(oChildNode)
                                    'AddNode(oChildNode)
                                End If


                            Catch ex As Exception
                                ''System.Diagnostics.Debug.Print("")
                            End Try

                        End If
                    Case Else

                        If Not IsNothing(LineCommand) Then

                            If LineCommand.StartsWith("*") Then
                                'It's a comment
                                AddCommentLine()

                            End If
                        End If

                End Select

            End While

            'Return String.Join(vbCrLf, Comments)
            poFromNode.ImageToolTip = FileID
            AddNodeComments(poFromNode, Comments)

            Return ""

        End Function

    End Class

    Public Class aSQLTextFile
        Inherits aTextFile

        Sub New(ByVal psFilePathName$)
            MyBase.New(psFilePathName)
        End Sub

        Public Overloads Sub GetNextLine(ByVal pViewState As StateBag)
            MyBase.GetNextLine()

            Dim bInComment = False

            If Not IsNothing(CurrentLine) AndAlso CurrentLine.Length > 0 Then

                CurrentLine = CurrentLine.Trim(";")

                While CurrentLine.Contains("/*") Or bInComment
                    bInComment = True
                    'This is a comment line, so add first fifty lines to an array
                    Dim sComment$ = CurrentLine.Replace("/*", "").Replace("*/", "").Trim(" ", Chr(9))
                    If sComment.Length Then
                        Comments(Comments.Length - 1) = "1," & sComment
                        ReDim Preserve Comments(Comments.Length)
                    End If

                    If CurrentLine.Contains("*/") And bInComment Then
                        bInComment = False
                    End If

                    MyBase.GetNextLine()
                    CurrentLine = CurrentLine.Trim(";")

                End While

                MyBase.GetLineTokens()

                CurrentLine = CurrentLine.Split("(")(0)

            End If
        End Sub

        Function ReadSQL(ByRef poFromNode As TreeNode, ByRef pViewState As StateBag)
            Dim bInComment As Boolean = False
            Dim sTarget$ = "0"

            While Not CurrentLine Is Nothing
                GetNextLine(pViewState)

                Select Case LineCommand
                    Case "insert", "update", "delete", "create", "truncate", "drop"
                        'Add node to tree
                        If Not LineTokens(1).ToUpper.StartsWith("INDEX") Then

                            Dim oChildNode As New TreeNode(CurrentLine.ToLower, "Data")
                            oChildNode.ToolTip = " "
                            oChildNode.ImageToolTip = FilePathName

                            poFromNode.ChildNodes.Add(oChildNode)
                            AddNode(oChildNode)
                        End If
                End Select
            End While

            poFromNode.ImageToolTip = FileID
            AddNodeComments(poFromNode, Comments)
            'Return String.Join(vbCrLf, Comments)

            Return ""

        End Function



    End Class


    Public Class aVisioApplication
        Implements IDisposable

        Public WithEvents _
            Application As Visio.InvisibleApp, _
            Document As Visio.Document, _
            mStencil As Visio.Document, _
            ConnectorMaster As Visio.Master, _
            Page As Visio.Page, _
            Window As Visio.Window

        Public Property Stencil() As Visio.Document
            Get
                Return mStencil
            End Get

            Set(ByVal value As Visio.Document)
                mStencil = value
                ConnectorMaster = mStencil.Masters("Dynamic Connector")

            End Set


        End Property

        Public Property PageName$()
            Get
                Return Page.Name
            End Get
            Set(ByVal value$)
                Page.Name = value
            End Set
        End Property

        Private Const TEMPLATEPATH = "C:\Program Files\Microsoft Office\Office12\1033\BASFLO_U.vss"

        Public Sub New(ByVal psPageName)
            Try
                'If IsNothing(Current.Session("VisioApplication")) Then
                '    Current.Session("VisioApplication") = Application
                'Else
                '    Application = Current.Session("VisioApplication")
                '    Try
                '        Stencil = Application.Documents.OpenEx(TEMPLATEPATH, 4)
                '    Catch ex As Exception
                '        Current.Session("VisioApplication") = Nothing
                '        Application = New Visio.InvisibleApp()
                '        Current.Session("VisioApplication") = Application
                '    End Try
                'End If
                'Dim vsoApplicationSettings As Visio.ApplicationSettings
                'Dim lngListSize As Long


                Application = New Visio.InvisibleApp()
                'System.Threading.Thread.Sleep(5000)

                'vsoApplicationSettings = Application.Settings
                'lngListSize = vsoApplicationSettings.ZoomOnRoll = True

                Stencil = Application.Documents.OpenEx(TEMPLATEPATH, 4)
                'System.Threading.Thread.Sleep(1000)

                Document = Application.Documents.Add("")
                'System.Threading.Thread.Sleep(1000)

                'Window = Application.Window
                'Dim nLeft#, nTop#, nHeight#, nWidth#
                'Window.GetViewRect(nLeft, nTop, nHeight, nWidth)
                'System.Threading.Thread.Sleep(3000)

                Page = Document.Pages(1)

                PageName = IO.Path.GetFileName(psPageName)

            Catch ex As System.Runtime.InteropServices.COMException
                Throw New Exception("Could not restart Visio", ex)

            Catch exNoVisio As InvalidCastException
                Throw New Exception("Could not start Visio", exNoVisio)

            End Try
        End Sub

        Private disposedValue As Boolean = False        ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    Try
                        ConnectorMaster.Close()
                        ConnectorMaster = Nothing
                    Catch
                    End Try

                    Try
                        Stencil.Close()
                        Stencil = Nothing
                    Catch
                    End Try

                    Try
                        Document.Close()
                        Document = Nothing
                    Catch
                    End Try

                    Try
                        Application.Quit()
                        Application = Nothing
                    Catch
                    End Try
                    'Give Visio a couple of seconds to shut down
                    'so it won't be running when the Viewer tries to open a file
                    'Viewer will throw an error if Visio object is in memory!!!!
                    System.Threading.Thread.Sleep(2000)
                    GC.Collect()
                End If

                ' TODO: free shared unmanaged resources
            End If
            Me.disposedValue = True
            GC.SuppressFinalize(Me)
        End Sub



#Region " IDisposable Support "
        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class

    Public Class aVisioTreeDrawing

#Region "Private Class Variables"

        Private Structure ofNodeShape
            Dim Node As TreeNode
            Dim Shape As Visio.Shape
            Dim Location As PointF
        End Structure

        Private WithEvents Application As Visio.InvisibleApp

        Private mPagesize As SizeF, _
                Location As PointF, _
                ShapeNodes As New ArrayList, _
                NodeShapes As New ArrayList, _
                ToShape As Visio.Shape, _
                FromShape As Visio.Shape, _
                PrevShape As Visio.Shape


#End Region

        Public FileName$
        Public DefaultFileName$

        Public CommentSize As SizeF
        Protected fMaxWidth As Single
        Public nPageCount As Integer
        Public sPageType$

        Public IsFragment As Boolean

        Public ShapesNode As New Specialized.HybridDictionary

        Public sdsBatCalledFiles, _
                sdsFileCommentLines, _
                sdsTextFiles, _
                sdsUsers, _
                sdsUserVSDFiles, _
                sdsCommentsDictionary, _
                sdsUtilTreeNodes, _
                sdsTreeNodes As SqlDataSource

        Protected CommentHeight% = ConfigurationManager.AppSettings("CommentHeight")
        Protected CommentWidth% = ConfigurationManager.AppSettings("CommentWidth")

        Public VisioApp As aVisioApplication

#Region "Constructors/Destructor"

        Public Sub New(ByRef poNode As TreeNode, ByVal psPageName$)
            '
            VisioApp = New aVisioApplication(psPageName)
            '
            'CalcPageHeight(poNode)

            'Need to calc page width
            mPagesize.Width = 8.5

            fMaxWidth = 8.5

            PageSize = mPagesize

            CommentSize.Width = CommentWidth  'inches
            CommentSize.Height = CommentHeight   'lines

            sdsTextFiles = Current.Session("sdsTextFiles")
            sdsTreeNodes = Current.Session("sdsTreeNodes")
            sdsUserVSDFiles = Current.Session("sdsUserVSDFiles")
            sdsBatCalledFiles = Current.Session("sdsBatCalledFiles")
            sdsFileCommentLines = Current.Session("sdsFileCommentLines")
            sdsUsers = Current.Session("sdsUsers")
            sdsCommentsDictionary = Current.Session("sdsCommentsDictionary")
            sdsUtilTreeNodes = Current.Session("sdsUtilTreeNodes")

        End Sub

        'Public Sub New(ByRef poNode As TreeNode, ByVal psPageName$, ByVal psTempatePath$)
        '    '
        '    Me.New(poNode, psPageName)
        '    Try
        '        '
        '        Stencil = Application.Documents.OpenEx(psTempatePath, 4)
        '    Catch ex As Exception
        '        Throw
        '    End Try
        'End Sub

#End Region

#Region "Properties"

        Public Property PageSize() As SizeF
            Get
                Return mPagesize
            End Get

            Set(ByVal pSize As SizeF)

                mPagesize = pSize

                Select Case mPagesize.Width
                    Case Is <= 8.5
                        mPagesize.Width = 8.5
                        sPageType = "Letter Portrait"
                        nPageCount = Fix(mPagesize.Height / 11.00001) + 1
                        '        If mPagesize.Height < 11 Then mPagesize.Height = 11

                    Case Is <= 11.5
                        mPagesize.Width = 11
                        sPageType = "Letter Landscape"
                        nPageCount = Fix(mPagesize.Height / 8.5) + 1

                    Case Else
                        mPagesize.Width = 14
                        sPageType = "Legal Landscape"
                        nPageCount = Fix(mPagesize.Height / 8.5) + 1

                        'Case Else
                        '    sPageType = "Plotter Sheet"
                        '    nPageCount = 1

                End Select



                'Set Width
                With VisioApp.Page.PageSheet
                    .CellsSRC(visSectionObject, visRowPage, 0).FormulaU = String.Format("{0} in", mPagesize.Width)

                    'Set Height
                    .CellsSRC(visSectionObject, visRowPage, 1).FormulaU = String.Format("{0} in", mPagesize.Height)

                    'Have to set paper type to match paper dimensions legal or letter
                    Dim sPaperType$ = IIf(mPagesize.Width > 11, "2", "1")

                    'Set paper type
                    .CellsSRC(visSectionObject, visRowPrintProperties, 17).FormulaU = sPaperType '2 is legal paper

                    '--Always Portrait
                    .CellsSRC( _
                     Visio.VisSectionIndices.visSectionObject, _
                     Visio.VisRowIndices.visRowPrintProperties, _
                     Visio.VisCellIndices.visPrintPropertiesPageOrientation). _
                     FormulaU = IIf(PageSize.Width > 8.5, "2", "1")

                End With
            End Set
        End Property

        Private ReadOnly Property ParentNodeShape(ByVal poNode As TreeNode) As ofNodeShape
            Get
                'Faster to go backwards for this 
                Dim oNodeShape As ofNodeShape = Nothing
                For i As Integer = ShapeNodes.IndexOf(poNode) - 1 To 0 Step -1
                    oNodeShape = NodeShapes(i)
                    If oNodeShape.Node Is poNode.Parent Then
                        Exit For
                    End If
                Next
                Return oNodeShape

            End Get
        End Property


#End Region

#Region "Methods"

        'Private Sub CalcPageHeight(ByRef poNode As TreeNode)
        'If poNode.Parent Is Nothing Then ' it's the root node
        '    mPagesize.Height = 2
        'ElseIf poNode.Parent.ChildNodes.Count = 1 Then
        'ElseIf poNode.Depth <= Me.Depth Or poNode.Target = "_parent" Then
        '    'Add as sibling below parent
        '    mPagesize.Height += 1
        'End If


        'For Each oNode As TreeNode In poNode.ChildNodes
        '    CalcPageHeight(oNode)
        'Next
        'End Sub

        Public Function BuildFlowchart$(ByRef poNode As TreeNode, ByVal psFileName$)

            DrawShape(poNode)
            'Place the children below the root off of the main line
            'For Each oNode As TreeNode In ptvwStructure.Nodes
            'Next

            mPagesize.Width = 8.5
            PageSize = mPagesize

            Current.Session("poNode") = poNode
            Return SaveFiles(psFileName)

        End Function

        Private Sub AddComment(ByRef poNode As TreeNode)
            Try
                If poNode.ImageToolTip.Trim.Length = 0 OrElse Not IsNumeric(poNode.ImageToolTip) Then
                    Exit Sub
                End If


                ''System.Diagnostics.Debug.Print("Adding comment node for " & poNode.Text)

                Dim oCommentShape As Visio.Shape = DropComment(poNode)

                sdsCommentsDictionary.SelectParameters!FileID.DefaultValue = poNode.ImageToolTip

                Dim dv As DataView = sdsCommentsDictionary.Select(Empty)
                If dv.Table.Rows.Count Then
                    'Get comments from dictionary 
                    oCommentShape.Text = dv.Table.Rows(0)!CommentLines

                Else
                    'Get comments from table
                    With sdsFileCommentLines
                        With .SelectParameters
                            !FileID.DefaultValue = poNode.ImageToolTip
                        End With
                        Dim iLines% = 0
                        Dim dy As DataView = .Select(Empty)
                        For Each oRow As DataRow In dy.Table.Rows
                            If oRow!IsVisibleLine And iLines < CommentHeight Then
                                oCommentShape.Text &= IIf(oCommentShape.Text.Length, vbCrLf, "") & oRow!CommentLine
                                iLines += 1
                            End If
                        Next
                    End With

                End If


                'If IsNumeric(poNode.ToolTip.Trim) AndAlso Val(poNode.ToolTip) > 1 Then
                'Else

                '    'Limit the lines of comments
                '    Dim saDelim$() = {vbCrLf}
                '    Dim saComments$() = poNode.ToolTip.Split(saDelim, StringSplitOptions.RemoveEmptyEntries)
                '    Array.Resize(saComments, CommentSize.Height)
                '    Dim oCommentShape As Visio.Shape = DropComment(poNode)
                '    oCommentShape.Text = String.Join(vbCrLf, saComments)

                'Keep up with max width
                If fMaxWidth < CommentSize.Width + Location.X + 0.5 Then '--1/2" right margin
                    fMaxWidth = CommentSize.Width + Location.X - 1
                End If
                'End If
            Catch ex As Exception
                Stop
            End Try


        End Sub

        Protected Function DropComment(ByVal poNode As TreeNode) As Visio.Shape
            'Draw the shape to the right
            Dim oFlowChartMaster As Visio.MasterClass = VisioApp.Stencil.Masters("Parallel Mode")

            'Location.X += nCommentLoc
            Dim nCommentOffset% = 3.25

            If poNode.Parent Is Nothing Then
                nCommentOffset = 3.5
            End If

            Dim oCommentShape As Visio.Shape = VisioApp.Page.Drop(oFlowChartMaster, _
             Location.X + nCommentOffset, Location.Y)

            'Hide shape lines
            oCommentShape.CellsSRC(visSectionObject, visRowLine, visLinePattern).FormulaU = "0"

            'Get the shape's text from the node's tooltip
            oCommentShape.Cells("Width").Formula = CommentSize.Width
            'Left align comment
            oCommentShape.CellsSRC(visSectionParagraph, 0, visHorzAlign).FormulaU = "0"

            Return oCommentShape

        End Function

        Protected Function sCleanText$(ByVal psText$)
            Return psText.Replace("_", "_" & Chr(32)) _
                         .Replace(".", Chr(32) & ".")

        End Function

        Protected Sub HighlightText(ByVal poShape As Visio.Shape, ByVal psFindText$)

            If poShape.Text.Contains(psFindText) Then
                Dim nTextStartsAt% = poShape.Text.IndexOf(psFindText)
                Dim nTextEndsAt% = nTextStartsAt + psFindText.Length - 1

                Dim vsoCharacters1 As Visio.Characters
                vsoCharacters1 = poShape.Characters
                vsoCharacters1.Begin = nTextStartsAt
                vsoCharacters1.End = nTextEndsAt
                vsoCharacters1.CharProps(visCharacterStyle) = 17.0#
                vsoCharacters1.CharProps(visCharacterColor) = 2.0#
            End If
        End Sub

        Public Sub DrawShape(ByRef poNode As TreeNode)
            'Need to cache these masters?
            Dim oFlowChartMaster As Visio.Master = VisioApp.Stencil.Masters(poNode.Value.Split(",")(0))

            If poNode.Parent Is Nothing Then ' it's the root node
                DrawRootNode(poNode, oFlowChartMaster)

            Else
                GetNextFromShape(poNode)

                'If poNode.Parent.ChildNodes.Count = 1 Then
                '    DrawOnlyChildNode(poNode, oFlowChartMaster)
                'Else
                DrawSiblingChildNode(poNode, oFlowChartMaster)
                'End If

            End If

            RecordNodeShapePair(poNode)

            'Recursively add this nodes chidnodes
            PrevShape = ToShape
            ToShape = Nothing

            DrawShapeChildNodes(poNode)
        End Sub

        Private Sub DrawRootNode(ByRef poNode As TreeNode, ByVal poFlowChartMaster As Visio.Master)
            'Determine starting location of map
            ' Start point measured from the bottom left corner.
            Location.X = 1
            Location.Y = PageSize.Height - 1
            '
            'Place the root node and locate the main line
            '
            'Draw the shape
            ToShape = DropShape(poNode, poFlowChartMaster, Location)

            ToShape.Cells("Width").Formula = "1.5 in"

            'Add comments to right of root node
            AddComment(poNode)

        End Sub

        Private Sub GetNextFromShape(ByRef poNode As TreeNode)
            'Get the shape for this node's parent        
            Dim iParent% = ShapeNodes.IndexOf(poNode.Parent)
            If iParent > -1 And iParent < NodeShapes.Count Then
                Dim oFromNodeShape As ofNodeShape = NodeShapes(ShapeNodes.IndexOf(poNode.Parent))
                FromShape = oFromNodeShape.Shape

                'If the previus shape is not the From shape
                'reset the x coordinate to the From shapes
                If Not (FromShape Is PrevShape) Then
                    Location.X = oFromNodeShape.Location.X
                    Location.X += 1
                End If
            End If
        End Sub

        Private Sub DrawOnlyChildNode(ByRef poNode As TreeNode, ByVal poFlowChartMaster As Visio.Master)
            'Add an only child to right of parent
            Location.X += 1.5

            'Draw the shape
            ToShape = DropShape(poNode, poFlowChartMaster, Location)

            'Draw the connection from the shapes parent
            DrawConnector("Right")

            'This needs to be in Draw 
            If poNode.ChildNodes.Count = 0 Or poNode.Target = "_top" Then                    'No children
                'Add comments to right of last child node
                AddComment(poNode)
            End If

        End Sub

        Private Sub DrawSiblingChildNode(ByRef poNode As TreeNode, ByVal poFlowChartMaster As Visio.Master)

            'If this is the first child, add a comment to the parent before creating the child
            '
            If poNode Is poNode.Parent.ChildNodes(0) Then
                'Or poNode.Depth = 1 Then
                'Add comments to right of parent nodes
                AddComment(poNode.Parent)
                Location.X += 1
            End If

            'Add as sibling to right and below parent
            Location.Y -= 1
            'if the y location is off the page then start a new page and advance beyond new page's top mar

            'Draw the child shape

            ToShape = DropShape(poNode, poFlowChartMaster, Location)


            If poNode.Checked Then
                'Don't connect yet
                Location.X -= 1
                '
            ElseIf poNode.Parent.Checked Then
                'Connect grandparent to left
                Dim oSaveFromShape As Visio.Shape = FromShape
                FromShape = ParentNodeShape(poNode.Parent).Shape
                DrawConnector("Bottom")
                'Connect parent to top
                FromShape = oSaveFromShape
                DrawConnector("Bottom", "Top")
                FromShape = oSaveFromShape
            Else
                DrawConnector("Bottom")
            End If

            If poNode.Target = "_top" Then 'Collapsed node get's a comment
                'Child node at depth limit, like an only child?
                AddComment(poNode)
            End If


        End Sub

        Private Sub RecordNodeShapePair(ByRef poNode As TreeNode)
            'Save node/shape pairs so can know parent's shape
            Dim oNodeShape As ofNodeShape
            With oNodeShape
                .Node = poNode
                .Shape = ToShape
                .Location.X = Location.X
                .Location.Y = Location.Y

                'Keep up with node's shape SO can quickly search for parent shapes
                NodeShapes.Add(oNodeShape)
                ShapeNodes.Add(poNode)

                'Add shape's path file name to list indexed by shape id
                ShapesNode.Add(ToShape.ID, poNode)

            End With
        End Sub

        Private Sub DrawShapeChildNodes(ByRef poNode As TreeNode)
            'If poNode.Depth < Me.Depth Or poNode.Target = "_parent" Or IsFragment = True Then

            If poNode.Expanded.Value = True Then
                For Each oNode As TreeNode In poNode.ChildNodes
                    DrawShape(oNode)
                Next
            End If
        End Sub

        Private Sub AddHyperLink(ByRef pvShape As Visio.Shape, ByRef poNode As TreeNode)
            Dim sFilePathName$ = poNode.ImageToolTip

            HighlightText(pvShape, ConfigurationManager.AppSettings("FileNotFound"))

            'If poNode.ChildNodes.Count > 0 And poNode.Depth = Me.Depth And poNode.Target <> "_parent" Then
            If poNode.Target = "_top" Then
                'Bold the edges of collapsed shapes
                'TODO Color the background of the shape gray to indicate it is collapsed. Easier to spot in <100% zoom.
                With pvShape
                    .CellsSRC(visSectionObject, visRowLine, visLineWeight).FormulaU = "2.08 pt"
                    .CellsSRC(visSectionObject, visRowFill, visFillForegnd).FormulaU = "14"
                End With
                'Add continuation shape node to indicate
            End If

            Dim hlinkobj As Visio.Hyperlink = pvShape.AddHyperlink

            'set hyperlink to the custom property url value
            With hlinkobj
                .Description = sFilePathName '& poNode.Target
                .Address = sFilePathName
            End With
        End Sub

        Private Sub DrawConnector(ByVal psFromBorder$, Optional ByVal psToBorder$ = "")
            Dim oConnector As Visio.Shape = VisioApp.Page.Drop(VisioApp.ConnectorMaster, 0, 0)
            Dim oBeginCell As Visio.Cell = oConnector.Cells("BeginX")
            oBeginCell.GlueTo(FromShape.Cells("Align" & psFromBorder))
            Dim oEndCell As Visio.Cell = oConnector.Cells("EndX")
            Dim sToBorder$ = "Left"
            If psToBorder.Length Then
                sToBorder = psToBorder
            End If
            oEndCell.GlueTo(ToShape.Cells("Align" & sToBorder))
            oConnector.SendToBack()
        End Sub

        Private Function DropShape(ByRef poNode As TreeNode, ByVal poFlowChartMaster As Visio.Master, ByVal Location As PointF) As Visio.Shape
            Dim oToShape As Visio.Shape = VisioApp.Page.Drop(poFlowChartMaster, Location.X, Location.Y)
            poNode.Value = poNode.Value.Split(",")(0) & "," & oToShape.ID
            oToShape.Text = sCleanText(poNode.Text)
            AddHyperLink(oToShape, poNode)

            'Save the node's shape id
            With sdsUtilTreeNodes
                With .UpdateParameters
                    !VSDFileID.DefaultValue = Current.Session("VSDFileID")
                    !NodeID.DefaultValue = poNode.NavigateUrl
                    !ShapeID.DefaultValue = oToShape.ID
                End With
                .Update()
            End With

            If poNode.Selected Then
                'oToShape.CreateSelection(Visio.VisSelectionTypes.visSelTypeSingle, Visio.VisSelectMode.visSelModeSkipSub)
            End If
            Return oToShape
        End Function

        Public Function SaveFiles$(ByVal psFileName$)
            'Save the visio files
            Dim saUserID$() = Current.Request.LogonUserIdentity.Name.Split("\")
            Dim sUserID$ = ""
            If Not IsNothing(saUserID) AndAlso saUserID.Length Then
                sUserID = "." & saUserID(saUserID.Length - 1)
            End If
            Dim sFileName$ = Path.GetFileNameWithoutExtension(psFileName)

            FileName = Current.Server.MapPath(String.Format("VSD\{0}{1}.vsd", sFileName, sUserID))
            DefaultFileName = Current.Server.MapPath(AppSettings("DefaultVSDFileName")).Replace(".vsd", sUserID & ".vsd")
            '
            Try
                Kill(FileName)
            Catch
            End Try

            'Resets the page width
            mPagesize.Width = fMaxWidth
            PageSize = mPagesize

            VisioApp.Document.SaveAs(FileName)


            Try
                ' Delete the previous version of the vsd file.
                Kill(DefaultFileName)
            Catch
            End Try
            VisioApp.Document.SaveAs(DefaultFileName)

            Return ""
            Exit Function

            'Save the file stats
            'Dim oFileStatsTable As New HIPO.aJobStatsFile()

            'Dim sText$ = oFileStatsTable.SaveFileStatsFile(FileName, DefaultFileName, ShapesNode)
            'Return sText

        End Function

#End Region


    End Class

    Public Class aPageSize

        Private mPageSize As SizeF
        Private Depth%
        Private MaxDepth%

        Public ReadOnly Property PageSize()
            Get
                Return mPageSize
            End Get

        End Property

        Public Sub New(ByRef pnDepth%, ByRef pnMaxDepth%)
            Depth = pnDepth
            MaxDepth = pnMaxDepth
        End Sub

        Public Sub CalcPageHeight(ByRef poNode As TreeNode)

            If poNode.Parent Is Nothing Then ' it's the root node
                mPageSize.Height = 2
            ElseIf poNode.Parent.Expanded.Value = True Then
                mPageSize.Height += 1
                If poNode.Expanded.Value = False Then
                    If poNode.ChildNodes.Count Then
                        poNode.Target = "_top"
                    End If
                Else
                    poNode.Target = ""
                End If
            Else
                Exit Sub
            End If
            'If poNode.Parent Is Nothing Then ' it's the root node
            '    mPageSize.Height = 2

            'ElseIf poNode.Parent.ChildNodes.Count = 1 Then 'it's an inline node so 
            '    If poNode.Expanded.Value = False Then
            '        poNode.Target = "_top"
            '    Else
            '        mPageSize.Height += 1
            '    End If
            'Else 'it's a sibling child node

            '    If poNode.Expanded.Value = True And poNode.Parent.Expanded.Value = True Then
            '        'Add as sibling below parent
            '        mPageSize.Height += 1
            '        poNode.Target = ""

            '    ElseIf poNode.Parent.Expanded.Value = True Then
            '        'Add as sibling below parent for first collapsed shape 
            '        If poNode.Parent.ChildNodes.Count > 1 And poNode.Expanded.Value = True Then 'it's not an inline shape
            '            mPageSize.Height += 1
            '        End If
            '        'Mark node as top collapsed shape
            '        poNode.Target = "_top"
            '    End If
            'End If
            For Each oNode As TreeNode In poNode.ChildNodes
                CalcPageHeight(oNode)
            Next

        End Sub

        Public Function SetPageDepth(ByVal poRootNode As TreeNode) As SizeF
            Try
                'Collapse nodes below depth
                poRootNode.ExpandAll()

                CollapseNodes(poRootNode)

                CalcPageHeight(poRootNode)

                'if poRootNode

                With mPageSize

                    .Width = 6 + Depth * 1.5

                    Select Case .Width
                        Case Is <= 8.5
                            .Width = 8.5

                            'Round up to next multiple of 11
                            .Height = 11 * ((.Height \ 11) + 1)


                        Case Is <= 11.5
                            .Width = 11

                        Case Else
                            .Width = 14

                    End Select
                End With

            Catch ex As Exception
                Diagnostics.Debug.Print("")
            End Try

            Return mPageSize


        End Function

        Public Sub CollapseNodes(ByRef poNode As TreeNode)
            If poNode.Depth > MaxDepth Then
                MaxDepth = poNode.Depth
            End If

            If poNode.Depth >= Depth And poNode.ChildNodes.Count > 0 Then
                If poNode.Checked And poNode.Depth = Depth Then 'it's an input card at Depth
                    'We want to expand it
                    'It's first child will be collapsed
                    poNode.Expanded = True
                Else
                    poNode.Expanded = False
                End If
            End If


            For Each oChildNode As TreeNode In poNode.ChildNodes
                CollapseNodes(oChildNode)
            Next
        End Sub


    End Class


    Public Structure ofHIPOTreeNode
        Dim ID%
        Dim ParentID%

        Dim ShapeId%
        Dim ShapeName$

        Dim Depth%
        Dim IsExpanded As Boolean
        Dim IsChecked As Boolean
        Dim IsSelected As Boolean

        Dim FileName$
        Dim FileExt$
        Dim FilePath$
        Dim FileDate As Date
        Dim FileSize&
        Dim CurrDate As Date
        Dim CurrSize&

        Dim NoteLines$

    End Structure

    Public Class aHIPOTree
        'This class is used to store, save and load tree-node data
        'Data is stored in simple vbcrlf delimited records, with fields delimited by tabs.
        'Data is accessed using ODBC.TEXT driver JET queries

        'Public TreeName$

        Public NodesList As ArrayList

        Public TreeNodes As Collection

        Public Sub New()

            NodesList = New ArrayList
            TreeNodes = New Collection

        End Sub

        Public Function NodesCount()
            NodesList.Add("")
            Return NodesList.Count
        End Function

        'Public Sub AddNode(ByRef poNode As TreeNode)
        '    Dim oNode As New ofHIPOTreeNode

        '    With oNode
        '        .ID = NodesList.Count + 1
        '        poNode.NavigateUrl = "#" & .ID
        '        If IsNothing(poNode.Parent) Then
        '            .ParentID = 0
        '        Else
        '            .ParentID = poNode.Parent.NavigateUrl.TrimStart("#")
        '            .IsChecked = poNode.Checked
        '            .IsSelected = poNode.Selected
        '            .IsExpanded = poNode.Expanded.Value
        '        End If

        '        .ShapeName = poNode.Value.Split(",")(0)

        '        If File.Exists(poNode.ImageToolTip) Then
        '            Dim oFileInfo As New FileInfo(poNode.ImageToolTip)
        '            .FileName = oFileInfo.Name
        '            .FilePath = oFileInfo.DirectoryName
        '            .FileExt = oFileInfo.Extension.Replace(".", "")
        '            .FileSize = oFileInfo.Length
        '            .FileDate = oFileInfo.LastWriteTime
        '        End If

        '        .NoteLines = Current.Server.UrlEncode(poNode.ToolTip)

        '        NodesList.Add(oNode)
        '        TreeNodes.Add(oNode, .ID)

        '    End With



        'End Sub

    End Class



    Public Class aJobStatsFile

        Public FileStatsTable As New DataTable
        Public FileStatsView As New DataView

        Public Structure ofFileStats
            Dim Path As String
            Dim Name As String
            Dim Size As Long
            Dim ModDate As Date
        End Structure

        Public ShapesNode As New Specialized.HybridDictionary


        Public Sub New()
            If IsNothing(Current.Session("FileStatsSet")) Then
                FileStatsTable = GetFileStatsFile()
            Else
                FileStatsTable = CType(Current.Session("FileStatsSet"), DataSet).Tables(0)
            End If

        End Sub


        Sub New(ByRef dgrd As DataGrid, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs)
            Me.New()
            FileStatsView = SortedFilesList(dgrd, e)
        End Sub


        Public Sub AddToFileStats(ByVal psFileName$, ByVal psFilePath$)
            Dim sFilePathName$ = Path.Combine(psFilePath, psFileName)
            'Output file info to a buffer here, to be saved to a text file
            Dim oFileStats As ofFileStats
            With oFileStats
                .Name = psFileName
                .Path = psFilePath.Replace("C:\Users\Dad\Documents\", "")
                Dim oFileInfo As IO.FileInfo = Computer.FileSystem.GetFileInfo(sFilePathName)
                If oFileInfo.Exists Then
                    .Size = oFileInfo.Length
                    .ModDate = oFileInfo.LastWriteTime
                End If
            End With


            'Get the current list from session into an array list of
            Dim alFileStats As New ArrayList
            If Not IsNothing(Current.Session("FileStatsList")) Then
                alFileStats.AddRange(CType(Current.Session("FileStatsList"), ArrayList))
            End If

            'If we don't have the file already, add it.
            If Not alFileStats.Contains(oFileStats) Then
                alFileStats.Add(oFileStats)
                Current.Session("FileStatsList") = alFileStats
            End If
        End Sub


        Public Function SaveFileStatsFile$(ByVal psVisioFileName$, ByVal psDefaultFileName$, _
         ByVal psdShapesNode As Specialized.HybridDictionary)

            'Create an xml file from the file stats
            'Get the current list from session into an array list of
            'Try
            '    ' Delete the previous version of the xml file.
            '    Kill(psDefaultFileName.ToLower.Replace("vsd", "xml"))
            'Catch
            'End Try

            'Try
            '    Kill(psVisioFileName.ToLower.Replace("vsd", "xml"))
            'Catch
            'End Try

            Dim alFileStats As New ArrayList
            If Not IsNothing(Current.Session("FileStatsList")) Then
                alFileStats.AddRange(CType(Current.Session("FileStatsList"), ArrayList))

                Dim sAllText$ = "<FileStats>"

                'Save Files List
                sAllText &= vbCrLf & "<FilesList>"
                For Each oFileStats As ofFileStats In alFileStats
                    With oFileStats
                        'Add this line to xml file
                        Dim sLine$ = String.Format("<FileLine Name='{0}' Path='{1}' Size='{2}' Date='{3}' />", _
                        .Name, .Path, .Size.ToString("###,###").PadLeft(10), .ModDate.ToString("yyyy-MM-dd   HH:mm"))
                        sAllText &= IIf(sAllText.Length, vbCrLf, "") & sLine
                    End With
                Next
                sAllText &= vbCrLf & "</FilesList>"

                'Save the ShapeIndex to PathFileName list
                'Serializing the node info
                sAllText &= vbCrLf & "<ShapeNodes>"
                For Each iShapeIndex As Integer In psdShapesNode.Keys
                    Dim oNode As TreeNode = psdShapesNode(iShapeIndex)
                    If Not IsNothing(oNode) Then
                        With oNode
                            Dim sLine$ = String.Format( _
                             "<ShapeLine ShapeID='{0}' Text='{1}' ImageToolTip='{2}' ValuePath='{3}'  />", _
                             iShapeIndex, .Text, .ImageToolTip, .ValuePath)
                            sAllText &= IIf(sAllText.Length, vbCrLf, "") & sLine
                        End With
                    End If
                Next
                sAllText &= vbCrLf & "</ShapeNodes>"

                'Save the treenodes
                sAllText &= vbCrLf & "<TreeView>"

                AddNodeLine(Current.Session("poNode"), sAllText)

                sAllText &= vbCrLf & "</TreeView>"

                sAllText &= vbCrLf & "</FileStats>"

                Try
                    Kill(psDefaultFileName.ToLower.Replace("vsd", "xml"))
                Catch
                End Try

                File.WriteAllText(psDefaultFileName.ToLower.Replace("vsd", "xml"), sAllText)

                Try
                    Kill(psVisioFileName.ToLower.Replace("vsd", "xml"))
                Catch
                End Try
                File.WriteAllText(psVisioFileName.ToLower.Replace("vsd", "xml"), sAllText)

            End If

            Return Me.FileStampSize(psVisioFileName)

        End Function

        Private Sub AddNodeLine(ByVal poNode As TreeNode, ByRef psAllText$)
            Try
                With poNode

                    Dim sShapeID$ = poNode.NavigateUrl

                    Dim sParentID$ = 0
                    If Not IsNothing(poNode.Parent) Then
                        sParentID$ = poNode.Parent.NavigateUrl
                    End If

                    Dim sImageToolTip$ = .ImageToolTip 'Current.Server.UrlPathEncode(.ImageToolTip)
                    Dim sTooltip$ = .ToolTip 'Current.Server.UrlEncode(.ToolTip)

                    Dim sLine$ = String.Format("<TreeNode ShapeId='{0}' ParentShapeID='{1}' Text='{2}' Value='{3}' ImageToolTip='{4}' Tooltip='{5}' Checked='{6}' Expanded='{7}' Target='{8}' Selected='{9}' />", _
                     sShapeID, sParentID, .Text, .Value, _
                     sImageToolTip, _
                     sTooltip, _
                     .Checked, .Expanded, .Target, .Selected)

                    psAllText &= vbCrLf & sLine

                    For Each oNode As TreeNode In poNode.ChildNodes
                        AddNodeLine(oNode, psAllText)
                    Next
                End With
            Catch ex As Exception
                Diagnostics.Debug.Print("")
            End Try
        End Sub


        Public Function FileStampSize$(ByVal psVisioFileName$)
            Dim sText$ = ""
            Dim oFileInfo As IO.FileInfo = Computer.FileSystem.GetFileInfo(psVisioFileName)
            If oFileInfo.Exists Then
                sText = String.Format("Diagram Created on {0}          [{1} bytes]           ", oFileInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm"), oFileInfo.Length.ToString("#,#"))
            End If

            Return sText
        End Function

        Private Function GetFileStatsFile() As DataTable
            Return Nothing
            Exit Function
            Dim FileStatsSet As New DataSet
            Try
                Dim sFileNamePath$ = Current.Server.MapPath(AppSettings("DefaultVSDFileName").ToUpper.Replace("VSD", "XML"))
                Dim reader As XmlTextReader = New XmlTextReader(sFileNamePath)
                FileStatsSet.ReadXml(reader)

                If FileStatsSet.Tables.Count > 1 Then

                    '@ Create new columns, Current Date Time
                    FileStatsSet.Tables(0).Columns.Add("CurrDate", GetType(String), "")
                    FileStatsSet.Tables(0).Columns.Add("CurrSize", GetType(String), "")
                    FileStatsSet.Tables(0).Columns.Add("CurrStatus", GetType(String), "iif(CurrSize='','Unknown',IIF(CurrDate>Date,'Changed','Current'))")

                    For Each oRow As DataRow In FileStatsSet.Tables(0).Rows
                        'Dim oSize As DataColumn = oRow("CurrSize")

                        Dim sPathFileName$ = IO.Path.Combine(oRow!Path, oRow!Name).Replace("H:", "C:\Users\Dad\Documents\H-Drive").Replace("L:", "C:\Users\Dad\Documents\L-Drive")

                        Dim oFileInfo As IO.FileInfo = Computer.FileSystem.GetFileInfo(sPathFileName)
                        If oFileInfo.Exists Then
                            oRow!CurrSize = oFileInfo.Length.ToString("#,#").PadLeft(10)
                            oRow!CurrDate = oFileInfo.LastWriteTime.ToString("yyyy-MM-dd   HH:mm")
                        Else
                            oRow!CurrSize = "" '.ToString("#,#").PadLeft(10)

                        End If

                    Next
                    Current.Session("FileStatsSet") = FileStatsSet

                    'Read the ShapeLine rows

                    'Deserialize the node - node that Valuepath stored in Value
                    ShapesNode.Clear()
                    For Each oRow As DataRow In FileStatsSet.Tables(1).Rows
                        Dim oNode As New TreeNode(oRow!Text)
                        oNode.ImageToolTip = oRow!ImageToolTip
                        oNode.Value = oRow!ValuePath
                        ShapesNode.Add(oRow!ShapeId, oNode) 's/b a TreeNode saved
                    Next
                    Current.Session("ShapesNode") = ShapesNode

                Else
                End If

            Catch exNF As FileNotFoundException


            Catch exSA As System.ArgumentException
                Throw New System.ArgumentException("Corrupted XML file for " & FileStatsSet.DataSetName & " dataset.", exSA)

            Finally
                If FileStatsSet.Tables.Count = 0 Then
                    'Create a dummy table to retunr a dummy record
                    'For some reason we dont have a default file 
                    FileStatsSet.Tables.Add(New DataTable())
                End If

            End Try

            Return FileStatsSet.Tables(0)


        End Function

        Private Function SortedFilesList(ByRef dgrdFilesList As DataGrid, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) As DataView
            FileStatsTable = CType(Current.Session("FileStatsSet"), DataSet).Tables(0)
            Dim dv As DataView = FileStatsTable.DefaultView

            Dim sSortExpression$ = e.SortExpression

            'Update the headers to show ? or ?
            For Each oCol As DataGridColumn In dgrdFilesList.Columns
                If oCol.SortExpression = e.SortExpression Then
                    'Update sort-direction indicator for column we arr currently sorting.
                    If oCol.HeaderText.EndsWith(" ^") Then
                        'Re-sort desc
                        oCol.HeaderText = oCol.HeaderText.Replace(" ^", " v")
                        sSortExpression &= " DESC"

                    ElseIf oCol.HeaderText.EndsWith(" v") Then
                        'Re-sort asc
                        oCol.HeaderText = oCol.HeaderText.Replace(" v", " ^")
                        sSortExpression = sSortExpression.Replace(" DESC", "")
                    Else
                        'First sort - ascending
                        oCol.HeaderText &= " ^"
                    End If
                Else
                    'Remove sort-direction indicator from prev sorted column
                    oCol.HeaderText = oCol.HeaderText.Replace(" ^", "").Replace(" v", "")
                End If
            Next

            'Sort the grid on the selected column
            dv.Sort = sSortExpression

            'Show the sort results
            Return dv
        End Function

    End Class



End Namespace
